﻿// Copyright 2008 (c) Michael Reichenauer, SWEDEN. All rights reserved.
//---------------------------------------------------------------------
using System;
using PostSharp.Laos;
using System.Reflection;

namespace PSMock
{
	/// <summary>
	/// Attribute to indicate which functions or methods that can be mocked by PSMock. Use either
	/// directly on a function e.g:
	/// 
	/// [MockFunctionAttribute]
	/// 
	/// or specify that all function names matching a pattern e.g:
	/// 
	/// // Support Mocking of all functions defined in this assembly
	/// [assembly: PSMock.MockFunction(AttributeTargetTypes = "*")]
	/// 
	/// or in a called assembly e.g.:
	/// 
	/// // Support Mocking of all functions defined in the .NET IO namespace
	/// [assembly: PSMock.MockFunction(AttributeTargetAssemblies = "mscorlib", 
	///                                AttributeTargetTypes = "System.IO.*")]
	/// 
	/// </summary>
	[Serializable]
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class 
		| AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Property 
		| AttributeTargets.Event, AllowMultiple = true)]
	public class MockFunctionAttribute : OnMethodInvocationAspect
	{
		int metadataToken;

		public override void RuntimeInitialize(MethodBase method)
		{
			base.RuntimeInitialize(method);
			metadataToken = method.MetadataToken;

		}

		public override void OnInvocation(MethodInvocationEventArgs eventArgs)
		{
			try
			{
				Mock.Intercept(eventArgs, metadataToken);
			}
			catch (Exception e)
			{
				// Exceptions thrown with a delegate body will be wrapped inside a TargetInvocationException
				// so we need to unwrap the original exception
				if (e is TargetInvocationException && e.InnerException != null)
					throw e.InnerException;
				else
					throw;
			}
		}
	}
}


